<?php
/**
 * FastApp.
 * 8/13/24
 * @Author 深色的海 (wx:deepsea_0024)
 * @Contact telegram:deepsea159
 */

namespace App\Game\Api\Service;

use App\Fastapp\Api\Service\BaseService;
use App\Fastapp\Listener\Event\AccountDailyActiveEvent;
use App\Fastapp\Model\AccountWallet;
use App\Fastapp\Model\FastappCategory;
use App\Game\Api\Service\Platform\ApibetService;
use App\Game\Api\Service\Platform\GameInterface;
use App\Game\Listener\Event\TaskSevenDaySignEvent;
use App\Game\Model\Game;
use App\Game\Model\GameAccountRtp;
use App\Game\Model\GameBet;
use App\Game\Model\GameCategory;
use App\Game\Model\GameFavorite;
use App\Game\Model\GameSymbol;
use App\Game\Model\GameTag;
use Mine\Helper\Str;

class GameService extends BaseService
{
    public function gameNum(): array
    {
        $k = 'gml:gameNum';
        $data = cache()->get($k);
        if ($data) return $data;
        $list = Game::query()->selectRaw('count(*) as num,GROUP_CONCAT(id) as ids,provider')
            ->groupBy('provider')->get()->mapWithKeys(function ($item) {
                return [$item->provider => [
                    'num' => $item->num,
                    'ids' => explode(',', $item->ids)
                ]];
            })->toArray();
        $gids = Game::query()->orderByDesc('sort')->pluck('id')->toArray();
        foreach ($list as $k => $v) {
            $ids = [];
            foreach ($gids as $gid) {
                if (in_array($gid, $v['ids'])) {
                    $ids[] = $gid;
                }
            }
            $v['ids'] = $ids;
            $list[$k] = $v;
        }
        cache()->set($k, $list, 300);
        return $list;
    }

    public function getProvider(): array
    {
        $k = 'gml:provider';
        $data = cache()->get($k);
        if ($data) return $data;
        $data = FastappCategory::query()
            ->select(['id', 'name', 'icon', 'view', 'code'])
            ->where(['scene' => 701])
            ->whereIn('code', array_keys(ApibetService::PR))
            ->orderByDesc('sort')
            ->get()->map(function ($item) {
                $item->name = fastapp_lang_text($item->name);
                return $item;
            })->toArray();
        cache()->set($k, $data, 300);
        return $data;
    }

    public function categoryRanking(): array
    {
        $sort = Game::withTrashed()->from('game as a')
            ->selectRaw('sum(a.`view`) as `view`,b.category_id')
            ->leftJoin('game_category as b', 'a.id', '=', 'b.game_id')
            ->groupBy('b.category_id')->get()->sortBy('num')
            ->pluck('view', 'category_id')->toArray();
        $res = FastappCategory::query()
            ->select(['id', 'name', 'icon'])
            ->whereIn('id', array_keys($sort))->get()->mapWithKeys(function ($item) {
                $item->name = fastapp_lang_text($item->name);
                return [$item->id => $item];
            })->toArray();

        $list = [];
        foreach ($sort as $id => $num) {
            if (!isset($res[$id])) continue;
            $v = $res[$id];
            $v['num'] = $num;
            $list[] = $v;
        }
        return ['list' => array_slice($list, 0, 10)];
    }

    public function gameRanking(): array
    {
        $list = Game::query()->select(['id', 'name', 'code', 'platform', 'provider', 'cover', 'view'])
            ->orderByDesc('view')->limit(10)->get()->map(function ($item) {
                $item->name = fastapp_lang_text($item->name);
                return $item;
            });
        return ['list' => $list];
    }

    public function list(array $param = []): array
    {
        $k = 'gml:' . md5(json_encode(array_filter($param)));
        $favoriteIds = [];
        try {
            $uid = get_uid();
            $res = get_user_cache(['seven_sign', 'type', 'symbol'], $uid);
            $param['symbol'] = $res['symbol'];
            if ($param['symbol'] == 'USDT') $param['symbol'] = 'USD';
            $today = date('Y-m-d');
            if (empty($res['seven_sign']) || $res['seven_sign'] != $today) {
                set_user_cache(['seven_sign' => $today], $uid);
                api_dispatch(new TaskSevenDaySignEvent($uid, (int)$res['type']));
                api_dispatch(new AccountDailyActiveEvent($uid, 'active'));
            }
            $favoriteIds = GameFavorite::query()->where(['user_id' => $uid, 'status' => 1])->pluck('game_id')->toArray();
            $k .= get_user_cache('currency', $uid);
        } catch (\Throwable) {
        }
        $data = cache()->get($k);
        if ($data) return $data;
        $data = $this->listData($param);
        foreach ($data['list'] as $item) {
            $item->is_favorite = in_array($item->id, $favoriteIds) ? 1 : 0;
        }
        cache()->set($k, $data, 300);
        return $data;
    }

    public function listData(array $param): array
    {
        $table = Game::getModel()->getTable();
        $query = Game::query();
        if (!empty($param['symbol'])) {
            $query->join(GameSymbol::getModel()->getTable() . ' as s', $table . '.id', '=', 's.game_id');
            $query->where('s.symbol', $param['symbol']);
        }
        if (!empty($param['category_id'])) {
            $query->join(GameCategory::getModel()->getTable() . ' as b', $table . '.id', '=', 'b.game_id');
            $query->whereIn('b.category_id', explode(',', $param['category_id']));
        }
        if (!empty($param['tag_id'])) {
            $query->join(GameTag::getModel()->getTable() . ' as c', $table . '.id', '=', 'c.game_id');
            $query->whereRaw('c.tag_id=' . ((int)$param['tag_id']));
        }
        if (!empty($param['provider'])) $query->where(['provider' => $param['provider']]);
        if (!empty($param['keyword'])) {
            $search = cache()->get('allgame');
            if (!$search || \Hyperf\Support\env('APP_ENV') == 'dev') {
                $search = Game::query()->get(['name', 'id'])->map(function ($item) {
                    $item->name = implode(',', array_column($item->name, 'text'));
                    return $item;
                })->pluck('name', 'id')->toArray();
                cache()->set('allgame', $search, 600);
            }
            $ids = [];
            foreach ($search as $id => $name) if (str_contains(strtolower($name), strtolower($param['keyword']))) $ids[] = $id;
            $query->whereIn($table . '.id', $ids);
        }
        $map = ['status' => 1];
        if (!empty($param['demo'])) $map['demo'] = 1;
        $query = $query
            ->with(['tag'])
            ->select([$table . '.id', 'name', 'code', 'platform', 'provider', 'cover', 'view'])
            ->where($map)->orderByDesc('sort');
        $perPage = empty($param['perPage']) ? 15 : (int)$param['perPage'];
        if (empty($param['all'])) {
            $count = $query->count();
            $res = $query->simplePaginate($perPage)->items();
        } else {
            $res = $query->get();
            $count = $res->count();
        }
        $list = [];
        foreach ($res as $item) {
            $item->setHidden(['tag']);
            $item->name = fastapp_lang_text($item->name);
            if ($item->tag->count() > 0) {
                $tag = [];
                foreach ($item->tag as $v) {
                    if ($v->tag) {
                        $tg = $v->tag->toArray();
                        $tg['name'] = fastapp_lang_text($tg['name']);
                        $tag[] = $tg;
                    }
                }
                $item->tags = $tag;

            } else $item->tags = [];
            $list[] = $item;
        }
        return ['list' => $list, 'count' => $count];
    }

    public function detail(int $id, string $ingress = 'device2'): array
    {
        $uid = get_uid();
        \Swoole\Coroutine::create(function () use ($id, $uid) {
            $service = new FavoriteService();
            $service->add($id, $uid, 1);
            Game::query()->where(['id' => $id])->increment('view');
        });
        $md = Game::query()->select(['id', 'name', 'icon', 'cover', 'code', 'type', 'platform', 'provider', 'hall', 'demo'])->where(['id' => $id])->firstOrFail();
        $md->name = fastapp_lang_text($md->name);
        /* @var GameInterface $cs */
        $cs = '\\App\\Game\\Api\\Service\\Platform\\' . Str::studly($md->platform) . 'Service';
        $symbol = get_user_cache('symbol', $uid);
        $map = ['user_id' => $uid, 'code' => $md->platform, 'symbol' => $symbol];
        if ($md->platform == 'apibet') $map['provider'] = $md->provider;
        $gac_id = GameAccountRtp::query()->where($map)->value('id');
        if ($symbol == 'USDT') $symbol = 'USD';
        if (!$gac_id) $cs::createUser($uid, $symbol, $md->provider);
        $cs::killUser($uid);
        $md->play_url = $cs::gamePlayUrl([
            'code' => $md->code,
            'type' => $md->type,
            'provider' => $md->provider,
            'demo' => $md->demo,
            'lang' => fastapp_lang(),
            'gac_id' => $gac_id ?: GameAccountRtp::query()->where($map)->value('id'),
            'user_id' => $uid,
            'gameid' => $id,
            'ingress' => $ingress,
        ]);
        if (!$md->demo) set_user_cache(['gameid' => $id, 'gamepl' => $md->platform, 'gamepr' => $md->provider], $uid);
        return $md->toArray();
    }

    public function bet(array $param): array
    {
        $map = ['user_id' => get_uid()];
        $query = GameBet::query()->select(['id', 'user_id', 'game_name', 'platform', 'result', 'amount', 'result_amount', 'created_at']);
        if (!empty($param['result'])) $map['result'] = $param['result'];
        if (!empty($param['start_at'])) $query->whereBetween('created_at', [$param['start_at'] . ' 00:00:00', $param['end_at'] . ' 00:00:00']);
        $paginate = $query->where($map)->orderByDesc('id')->simplePaginate();
        $list = [];
        foreach ($paginate->items() as $item) {
            $list[] = $item;
        }
        return ['list' => $list];
    }

    public function logType(): array
    {
        return [
            [
                'label' => fastapp_t('fastapp.account'),
                'value' => 'account',
                'children' => [
                    ['label' => fastapp_t('pay.recharge'), 'value' => 1],
                    ['label' => fastapp_t('pay.withdrawal'), 'value' => 2],
                ]
            ],
            [
                'label' => fastapp_t('game.bet'),
                'value' => 'game',
                'children' => [
                    ['label' => fastapp_t('game.win'), 'value' => 1],
                    ['label' => fastapp_t('game.lose'), 'value' => 2],
                ]
            ]
        ];
    }

    public function statistics(array $param): array
    {
        $map['user_id'] = get_uid();
        $query = GameBet::query();
        if (!empty($param['game_id'])) $map['game_id'] = $param['game_id'];
        if (!empty($param['start_at'])) $query->whereBetween('created_at', [$param['start_at'] . ' 00:00:00', $param['end_at'] . ' 00:00:00']);
        $query->where($map);
        $res = $query->selectRaw('sum(result_amount) as result_amount,result')->groupBy('result')->pluck('result_amount', 'result')->toArray();

        return [
            'total' => bcadd(bcadd(($res[1] ?? '0'), ($res[2] ?? '0'), 2), ($res[3] ?? '0'), 2),
            'win' => bcadd($res[2] ?? '0', '0', 2),
            'lose' => bcadd($res[3] ?? '0', '0', 2),
        ];
    }

    public function balance(string $symbol): array
    {
        $uid = get_uid();
        $pl = get_user_cache('gamepl', $uid);
        set_user_cache(['symbol' => $symbol], $uid);
        $wallet = '';
        if ($pl == ApibetService::CODE) {
            $wallet = ApibetService::syncBalance($symbol, $uid);
        }
        if (!$wallet) $wallet = AccountWallet::query()->where(['user_id' => $uid, 'symbol' => $symbol])->first();
        $data = $wallet->toArray();
        $data['currency'] = get_currency_cache($symbol);
        return $data;
    }
}